#include "AutoFind.h"

// 判断是否具有管理员权限
static bool IsElevated() {
#if defined(_WIN32) || defined(_WIN64)
    BOOL isElevated = FALSE;
    HANDLE token = NULL;

    // 打开当前进程的访问令牌
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
        PSID administratorsGroup;
        SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;

        // 创建一个 SID 表示管理员组（S-1-5-32-544）
        if (AllocateAndInitializeSid(&SIDAuthWorld, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administratorsGroup)) {
            // 检查当前进程是否属于管理员组
            CheckTokenMembership(NULL, administratorsGroup, &isElevated);
            FreeSid(administratorsGroup);
        }
        CloseHandle(token);
    }

    return isElevated == TRUE;
#elif defined(__linux__)
    return geteuid() == 0; // 检查有效用户 ID 是否为 0
#else
#error "Unsupported operating system"
#endif

}

// 获取当前登录用户名
static std::string GetCurrentUsername() {
#if defined(_WIN32) || defined(_WIN64)
    DWORD bufferSize = 256 + 1; // 用户名最大长度 + 1
    char username[256 + 1];
    DWORD usernameLength = bufferSize;

    if (GetUserName(username, &usernameLength)) {
        return std::string(username);
    } else {
        return "Unknown";
    }
#elif defined(__linux__)
    const char* username = getlogin();
    if (username) {
        return std::string(username);
    } else {
        struct passwd* pwd = getpwuid(geteuid());
        if (pwd) {
            return std::string(pwd->pw_name);
        }
    }
    return "Unknown";
#else
#error "Unsupported operating system"
#endif
}


void CMDHandle::handleError(const char *err,bool test_over) {
    SKPacket *packet = (struct SKPacket *)malloc(sizeof(struct SKPacket));
    cJSON *root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root,"cmd",SocketCMD::error);
    cJSON_AddStringToObject(root,"data",err);
    cJSON_AddBoolToObject(root,"test",test_over);
    log_error(err);
    auto data = cJSON_PrintUnformatted(root);
    packet->data = (uint8_t*)data;
    packet->size = strlen(data);
    send_queue.Push(packet);
    cJSON_Delete(root);
}

void CMDHandle::handlePing(std::string id){
    std::ostringstream _stream;
#if defined(_WIN32) || defined(_WIN64)
    _stream << "msg * ";
#elif defined(__linux__)
    _stream << "notify-send 'Auto Find' ";
#else
#error "Unsupported operating system"
#endif
    _stream << "'id: "<<id<<"'";
    system(_stream.str().c_str());
}

void CMDHandle::handleHello(cJSON *id) {

    if(cJSON_IsString(id)){
        ///服务器下发了ID号
        std::ofstream id_config("id.txt", std::ios::trunc);
        log_info("New ID from Server:%s",cJSON_GetStringValue(id));
        id_config << std::string(cJSON_GetStringValue(id));
        id_config.close();
    }
    std::ifstream _id("id.txt");
    std::string __id;
    ///上报基本信息以及有无ID号
    cJSON *root = cJSON_CreateObject();
    cJSON *cfg;
    if(_id.is_open()){
        std::getline(_id, __id);
        _id.close();
    }
    if(__id.compare("") == 0){
        cJSON_AddStringToObject(root,"id",__id.c_str());
        cJSON_AddNumberToObject(root,"cmd",SocketCMD::hello);
//        SKPacket *packet = (struct SKPacket *)malloc(sizeof(struct SKPacket));
//        auto data = cJSON_PrintUnformatted(root);
//        // std::cout << data << std::endl;
//        packet->data = (uint8_t*)data;
//        packet->size = strlen(data);
//        send_queue.Push(packet);
        SEND_PACK(root);
        cJSON_Delete(root);
        return;
    }
    std::ifstream config("config.json");
    if(config.is_open()){
        std::stringstream buffer;
        buffer << config.rdbuf();
        cfg = cJSON_Parse(buffer.str().c_str());
        if(!cfg){
            handleError("config parse err");
            cfg = cJSON_CreateObject();
        }
    }else{
        handleError("config open err,exist?");
        cfg = cJSON_CreateObject();
    }
    std::ostringstream version_stream;
#if defined(_WIN32) || defined(_WIN64)
    version_stream << "Windows ";
    if (IsWindows10OrGreater()) {
        version_stream << "10+";
    } else if (IsWindows8OrGreater()) {
        version_stream << "8";
    } else if (IsWindows7OrGreater()) {
        version_stream << "7";
    }
#elif defined(__linux__)
    /// "Linux(Ubuntu/Kylin):$VERSION"
    version_stream << "Linux(";
    std::ifstream os_condfig("/etc/os-release");
    if (!os_condfig.is_open()) {
        handleError("config open /etc/os-release err,exist?");
    }else{
        std::string line;
        std::string osName;
        while (std::getline(os_condfig, line)) {
            size_t pos = line.find('=');
            if (pos != std::string::npos) {
                std::string key = line.substr(0, pos);
                std::string value = line.substr(pos + 1);
                if(key.compare("NAME") == 0){
                    // 去掉引号
                    if (value.front() == '"' && value.back() == '"') {
                        value = value.substr(1, value.size() - 2);
                    }
                    version_stream << value << "):";
                    osName = value;
                }else if(key.compare("VERSION") == 0){
                    // 去掉引号
                    if (value.front() == '"' && value.back() == '"') {
                        value = value.substr(1, value.size() - 2);
                    }
                    version_stream << value;
                    break;
                }
            }
        }
        os_condfig.close();
        if(osName.compare("Kylin") == 0){
            std::ifstream kylin("/etc/kylin-build");
            if (!kylin.is_open()) {
                handleError("can\'t open /etc/kylin-build,exist?");
            }else{
                std::string line;
                while (std::getline(kylin, line)) {
                    size_t pos = line.find('=');
                    if (pos != std::string::npos) {
                        std::string key = line.substr(0, pos);
                        if(key.compare("TIME") == 0){
                            std::string value = line.substr(pos + 1);
                            if (value.front() == '"' && value.back() == '"') {
                                value = value.substr(1, value.size() - 2);
                            }
                            cJSON_AddStringToObject(root,"build",value.c_str());
                        }
                    }
                }
                kylin.close();
            }
        }
    }
#else
#error "Unsupported operating system"
#endif
    char hostName[256] = {0};
    gethostname(hostName,sizeof (hostName));

    cJSON_AddStringToObject(root,"id",__id.c_str());
    cJSON_AddNumberToObject(root,"cmd",SocketCMD::hello);
    cJSON_AddStringToObject(root,"os",version_stream.str().c_str());
    cJSON_AddStringToObject(root,"host",std::string(hostName).c_str());
    cJSON_AddStringToObject(root,"version",PROJECT_VERSION);
    cJSON_AddStringToObject(root,"time",PROJECT_COMPILE_TIME);
    cJSON_AddBoolToObject(root,"root",IsElevated());
    cJSON_AddStringToObject(root,"name",GetCurrentUsername().c_str());
    cJSON_AddItemToObject(root,"config",cfg);

    SEND_PACK(root);
    cJSON_Delete(root);

    //handleLog();
}

void CMDHandle::handleDmesg(std::string file)
{

    cJSON *root = cJSON_CreateObject();
    system(("dmesg > './logs/"+file+".log'").c_str());
    std::ifstream log_file("logs/"+file+".log",std::ios::binary);
    if(log_file.is_open()){
        // 移动到文件末尾
        log_file.seekg(0, std::ios::end);
        std::streamsize fileSize = log_file.tellg();
        // 移动到文件开头
        log_file.seekg(0, std::ios::beg);
        // 逐块读取文件内容
        // std::vector<char> buffer(bufferSize);
        char* buffer = (char *)malloc(MAX_FILE_SIZE + 1); // 分配内存，+1 用于存储 '\0'
        std::streamsize allRead = 0;
        cJSON_AddNumberToObject(root,"cmd",SocketCMD::logs);
        cJSON_AddNumberToObject(root,"total",(double_t)fileSize);
        cJSON_AddStringToObject(root,"name",(file+".log").c_str());
        std::streamsize bytesRead = 0;
        do{
            log_file.read(buffer, MAX_FILE_SIZE);
            bytesRead = log_file.gcount();
            // 处理读取到的内容
            // std::cout << "Read " << bytesRead << " bytes" << std::endl;
            //if(bytesRead <= 0) break;
            buffer[bytesRead] = '\0';
            // 这里可以将读取到的内容写入其他地方或进行处理
            {
                allRead += bytesRead;
                cJSON_AddNumberToObject(root,"count",(double_t)allRead);
                cJSON_AddStringToObject(root, "data", buffer);
                SEND_PACK(root);
                cJSON_DeleteItemFromObject(root,"count");
                cJSON_DeleteItemFromObject(root, "data");
            }
        }while(bytesRead == MAX_FILE_SIZE);
        delete buffer;
        // 关闭文件
        log_file.close();
    }else{
        handleError(("open " + file + " err,exist?").c_str(),true);
        goto err;
    }

    err:
    cJSON_Delete(root);
}

void CMDHandle::handleLog()
{
    cJSON *root = cJSON_CreateObject();
    cJSON *array = cJSON_CreateArray();

#if defined(_WIN32) || defined(_WIN64)
    const char *dir_path = "logs\\*"; // 注意使用通配符 '*' 和双反斜杠 '\\'

    // 初始化搜索句柄和结构
    WIN32_FIND_DATA ffd;
    HANDLE hFind = INVALID_HANDLE_VALUE;

    // 打开目录搜索句柄
    hFind = FindFirstFile(dir_path, &ffd);
    if (hFind == INVALID_HANDLE_VALUE) {
        handleError("can\'t open logs");
        return ;
    }

    // 读取目录中的文件
    do {
        // 跳过'.'和'..'目录
        if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0) {
            continue;
        }
        cJSON_AddItemToArray(array,cJSON_CreateString(ffd.cFileName));
    } while (FindNextFile(hFind, &ffd) != 0);

    // 关闭搜索句柄
    FindClose(hFind);
#elif defined(__linux__)
    const char *dir_path = "logs";
    // 打开目录
    DIR *dir = opendir(dir_path);
    if (dir == NULL) {
        handleError("can\'t open logs");
        return;
    }

    // 读取目录中的文件
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        // 跳过'.'和'..'目录
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }
        cJSON_AddItemToArray(array,cJSON_CreateString(entry->d_name));
    }
    // 关闭目录
    closedir(dir);
#else
#error "Unsupported operating system"
#endif
    cJSON_AddNumberToObject(root,"cmd",SocketCMD::logs);
    cJSON_AddItemToObject(root,"data",array);
    SEND_PACK(root);

    cJSON_Delete(root);
}

void CMDHandle::handleCMD(std::string cmd)
{
    cJSON *root = cJSON_CreateObject();

    cJSON_AddNumberToObject(root,"cmd",SocketCMD::cmd);
    SEND_PACK(root);
    cJSON_Delete(root);
}

void CMDHandle::handleFiles(cJSON *paths,int dir)
{
    cJSON *root = cJSON_CreateObject();

    cJSON_AddNumberToObject(root,"cmd",SocketCMD::file);
    cJSON_AddNumberToObject(root,"dir",dir);
    if(dir == 2){
        cJSON *array = cJSON_CreateArray();
        cJSON *_paths = cJSON_CreateArray();
        std::string path = "/";
        int size = cJSON_GetArraySize(paths);
        for(int i=0;i<size;i++){
            cJSON *t = cJSON_GetArrayItem(paths,i);
            path += "/" + std::string(cJSON_GetStringValue(t));
            cJSON_AddItemToArray(_paths,cJSON_CreateString(cJSON_GetStringValue(t)));
        }
        log_info("path %d:%s",dir,path.c_str());
#if defined(_WIN32) || defined(_WIN64)

        // 初始化搜索句柄和结构
        WIN32_FIND_DATA ffd;
        HANDLE hFind = INVALID_HANDLE_VALUE;

        // 打开目录搜索句柄
        hFind = FindFirstFile(path.c_str(), &ffd);
        if (hFind == INVALID_HANDLE_VALUE) {
            handleError(("can\'t open " + path).c_str());
            return ;
        }

        // 读取目录中的文件
        do {
            // 跳过'.'和'..'目录
            if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0) {
                continue;
            }
            cJSON_AddItemToArray(array,cJSON_CreateString(ffd.cFileName));
        } while (FindNextFile(hFind, &ffd) != 0);

        // 关闭搜索句柄
        FindClose(hFind);
#elif defined(__linux__)
        // std::cout << DT_UNKNOWN << std::endl;   //0未知文件类型
        // std::cout << DT_FIFO << std::endl;      //1FIFO 文件（命名管道）
        // std::cout << DT_CHR << std::endl;       //2字符设备文件
        // std::cout << DT_DIR << std::endl;       //4目录文件
        // std::cout << DT_BLK << std::endl;       //6块设备文件
        // std::cout << DT_REG << std::endl;       //8普通文件
        // std::cout << DT_LNK << std::endl;       //10符号链接文件
        // std::cout << DT_SOCK << std::endl;      //12套接字文件
        // std::cout << DT_WHT << std::endl;       //14白洞（whiteout）文件
        // 打开目录
        DIR *dir = opendir(path.c_str());
        if (dir == NULL) {
            handleError(("can\'t open " + path).c_str());
            return;
        }

        // 读取目录中的文件
        struct dirent *entry;
        while ((entry = readdir(dir)) != NULL) {
            // 跳过'.'和'..'目录
            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
                continue;
            }
            cJSON *en = cJSON_CreateObject();
            switch(entry->d_type){
                case DT_REG:cJSON_AddNumberToObject(en,"type",0);break;
                case DT_DIR:cJSON_AddNumberToObject(en,"type",1);break;
                case DT_LNK:cJSON_AddNumberToObject(en,"type",2);break;
                default:
                    cJSON_AddNumberToObject(en,"type",-1);
                break;
            }
            cJSON_AddStringToObject(en,"name",entry->d_name);
            cJSON_AddItemToArray(array,en);
        }
        // 关闭目录
        closedir(dir);
#else
#error "Unsupported operating system"
#endif
        cJSON_AddItemToObject(root,"data",array);
        cJSON_AddItemToObject(root,"paths",_paths);
        SEND_PACK(root);
        cJSON_Delete(root);
    }else if(dir == 1){
        std::string path = "/";
        cJSON *dev = cJSON_GetObjectItem(paths, "dev");
        int size = cJSON_GetArraySize(dev);
        for(int i=0;i<size;i++){
            cJSON *t = cJSON_GetArrayItem(dev,i);
            path += "/" + std::string(cJSON_GetStringValue(t));
        }
        path+="/" + std::string(cJSON_GetStringValue(cJSON_GetObjectItem(paths, "name")));
        char *local = cJSON_GetStringValue(cJSON_GetObjectItem(paths, "local"));
        log_info("path %s -> %s",path.c_str(),local);
        cJSON_AddStringToObject(root,"name",local);
        std::ifstream log_file(path,std::ios::binary);
        if(log_file.is_open()){
            // 移动到文件末尾
            log_file.seekg(0, std::ios::end);
            std::streamsize fileSize = log_file.tellg();

            // 移动到文件开头
            log_file.seekg(0, std::ios::beg);
            // 逐块读取文件内容
            // std::vector<char> buffer(bufferSize);
            char* buffer = (char *)malloc(MAX_FILE_SIZE + 1); // 分配内存，+1 用于存储 '\0'
            std::streamsize allRead = 0;
            cJSON_AddNumberToObject(root,"total",(double_t)fileSize);
            std::streamsize bytesRead = 0;
            do{
                log_file.read(buffer, MAX_FILE_SIZE);
                bytesRead = log_file.gcount();
                // 处理读取到的内容
                std::cout << "Read " << bytesRead << " bytes" << std::endl;
                //if(bytesRead <= 0) break;
                buffer[bytesRead] = '\0';
                // 这里可以将读取到的内容写入其他地方或进行处理
                {
                    allRead += bytesRead;
                    cJSON_AddNumberToObject(root,"count",(double_t)allRead);
                    cJSON_AddStringToObject(root, "data", buffer);
                    SEND_PACK(root);
                    cJSON_DeleteItemFromObject(root,"count");
                    cJSON_DeleteItemFromObject(root, "data");
                }
            }while(bytesRead == MAX_FILE_SIZE);
            delete buffer;
            // 关闭文件
            log_file.close();
        }else{
            handleError(("open " + path + " err,exist?").c_str());
        }
        cJSON_Delete(root);
        return;
    }else if(dir == 0){
        std::string path = "/";
        cJSON *dev = cJSON_GetObjectItem(paths, "dev");
        int size = cJSON_GetArraySize(dev);
        for(int i=0;i<size;i++){
            cJSON *t = cJSON_GetArrayItem(dev,i);
            path += "/" + std::string(cJSON_GetStringValue(t));
        }
        path+="/" + std::string(cJSON_GetStringValue(cJSON_GetObjectItem(paths, "name")));
        int count = cJSON_GetObjectItem(paths, "count")->valueint;
        int total = cJSON_GetObjectItem(paths, "total")->valueint;
        char* buffer = (char *)malloc(count);
        std::ifstream ff(path);
        bool file_exists = static_cast<bool>(ff);
        ff.close();
        std::fstream fff;
        if(file_exists){
            bool first = cJSON_IsTrue(cJSON_GetObjectItem(paths, "first"));
            if(first){
                // 重建文件（清除原有内容并打开）
                fff.open(path, std::ios::out | std::ios::trunc | std::ios::binary);
            }else{
                // 追加写入
                fff.open(path, std::ios::out | std::ios::app | std::ios::binary);
            }
        }else{
            // 文件不存在，创建文件并写入内容
            fff.open(path, std::ios::out|std::ios::binary);
        }
        if(!fff.is_open()){
            handleError(("open/create " + path + " err!").c_str());
            cJSON_Delete(root);
            return;
        }
        cJSON *_data = cJSON_GetObjectItem(paths, "data");
        for(int i=0;i<count;i++){
            cJSON *t = cJSON_GetArrayItem(_data,i);
            buffer[i] = t->valueint;
        }
        fff.write(buffer, count); // 使用 write 函数写入
        fff.close();
        cJSON_AddNumberToObject(root,"count",count);
        cJSON_AddNumberToObject(root,"total",total);
        //std::cout<<"path:"<<path<<",count:"<<count<<",total:"<<total<<std::endl;
    }else{
        handleError(("dir num: error!" + std::to_string(dir)).c_str());
        cJSON_Delete(root);
        return;
    }
}